package com.weizhizs.assistant.code.dao;

import com.weizhizs.assistant.code.config.DbConfig;
import com.weizhizs.assistant.code.config.ParamConfig;
import com.weizhizs.assistant.code.enums.TableTypeEnum;
import com.weizhizs.assistant.code.helper.TableHelper;
import com.weizhizs.assistant.code.vo.ColumnVO;
import com.weizhizs.assistant.code.vo.EnumVO;
import com.weizhizs.assistant.code.vo.TableVO;
import com.weizhizs.assistant.utils.StringUtils;
import org.apache.commons.lang3.ObjectUtils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class GeneratorDao {

    private static GeneratorDao _INSTANCE;

    public static GeneratorDao getInstance() {
        if (null == _INSTANCE) {
            _INSTANCE = new GeneratorDao();
            _INSTANCE.initDB(DbConfig.getInstance());
        }
        return _INSTANCE;
    }

    private DbConfig config;

    private Connection connection;

    private void initDB(DbConfig dbConfig) {
        this.config = dbConfig;

        // 创建连接
        Connection con = null;

        try {
            Class.forName(dbConfig.getDbDriver());
            con = DriverManager.getConnection(
                    dbConfig.getDbUrl(),
                    dbConfig.getDbUserName(),
                    dbConfig.getDbPassword());
        } catch (Exception e) {
            e.printStackTrace();
        }

        this.connection = con;
    }

    public Map<String, String> getTableList(String preTableName,
                                            String preFilterName) {
        String sql = "SELECT table_name, table_comment FROM information_schema.tables "
                + " WHERE table_schema = '" + config.getDbSchema() + "'"
                + " AND table_type = 'BASE TABLE'";
        // 查要生成实体类的表
        if (null == preTableName || preTableName.isEmpty() || "*".equals(preTableName.trim())) {
        } else {
            sql = sql + " AND table_name LIKE '" + preTableName + "%'";
        }

        Map<String, String> ret = new HashMap<>(16);

        try {
            Statement stat = connection.createStatement();
            ResultSet rs = stat.executeQuery(sql);

            while (rs.next()) {
                String value = rs.getString(1);
                String comment = rs.getString(2);
                if (null != preFilterName && !"".equals(preFilterName.trim()) &&
                        value.startsWith(preFilterName)) {
                    continue;
                }
                ret.put(value, comment);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return ret;
    }

    public boolean loadTableColumns(TableVO tableVO) {
        String tableName = tableVO.getTableName();

        String sql = "SELECT COLUMN_NAME, COLUMN_COMMENT, " +
                " COLUMN_KEY, DATA_TYPE, EXTRA, IS_NULLABLE, COLUMN_DEFAULT, " +
                " CHARACTER_MAXIMUM_LENGTH " +
                " FROM INFORMATION_SCHEMA.COLUMNS " +
                " WHERE table_schema = '" + config.getDbSchema() + "'" +
                " AND table_name = '" + tableName + "'" +
                " ORDER BY ORDINAL_POSITION";

        boolean havePk = false;
        Statement stat;
        try {
            stat = connection.createStatement();
            ResultSet rs = stat.executeQuery(sql);
            List<String> enumNames = new ArrayList<>();
            while (rs.next()) {
                ColumnVO columnVO = new ColumnVO();

                String columnName = rs.getString(1);
                columnVO.setColumnName(columnName);
                columnVO.setDataType(rs.getString(4));

                String attrName = TableHelper.columnNameToAttrName(columnName);
                columnVO.setAttrName(StringUtils.firstToLowerCase(attrName));
                columnVO.setAttrType(TableHelper.sqlTypeToJavaType(columnVO.getDataType()));

                String nullable = rs.getString(6);
                columnVO.setIsNullable("YES".equalsIgnoreCase(nullable));

                String defaultValue = rs.getString(7);
                columnVO.setDefaultValue(defaultValue);

                String charLength = rs.getString(8);
                if (null == charLength || charLength.isEmpty()) {
                    columnVO.setCharLength(0);
                } else {
                    try {
                        columnVO.setCharLength(Integer.parseInt(charLength));
                    } catch (Exception ignore) {
                        columnVO.setCharLength(0);
                    }
                }

                String colComment = rs.getString(2);
                if (colComment == null || "".equals(colComment.trim())) {
                    colComment = columnName;
                }

                columnVO.setComments(colComment);

                String enumName = readEnumName(colComment);
                if (null != enumName) {
                    enumNames.add(enumName);
                    columnVO.setEnumList(getEnumList().get(enumName));
                }

                String pk = rs.getString(3);
                if ("PRI".equals(pk)) {
                    columnVO.setIsAutoKey("auto_increment".equalsIgnoreCase(rs.getString(5)));
                    tableVO.setPk(columnVO);
                    havePk = true;
                } else {
                    tableVO.getColumns().add(columnVO);
                }
                if (null == tableVO.getQueryField() &&
                        "String".equals(columnVO.getAttrType()) &&
                        (columnVO.getColumnName().contains("_name") ||
                                columnVO.getColumnName().contains("_code") ||
                                columnVO.getColumnName().contains("_type") ||
                                (
                                        !"upd_prog".equals(columnVO.getColumnName()) &&
                                                !"upd_id".equals(columnVO.getColumnName())
                                ))) {
                    tableVO.setQueryField(columnVO);
                }
            }
            tableVO.setEnumNames(enumNames);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return havePk;
    }

    /**
     *
     * @return  Map<param_type, type下的所有枚举项>
     */
    public Map<String, List<EnumVO>> getEnumList() {
        String sql = "SELECT * FROM "+ ParamConfig.getInstance().getEnumTable();
        Map<String, List<EnumVO>> ret = new HashMap<>(64);
        List<EnumVO> enumList = new ArrayList<>();

        try {
            Statement stat = connection.createStatement();
            ResultSet rs = stat.executeQuery(sql);
            while (rs.next()) {
                EnumVO enumVO = new EnumVO();
                enumVO.setParamType(rs.getString("param_type"));
                enumVO.setTypeName(rs.getString("type_name"));
                enumVO.setParamCode(rs.getString("param_code"));
                enumVO.setParamName(rs.getString("param_name"));
                enumVO.setParamKey(rs.getString("param_key"));
                enumVO.setParamValue(rs.getString("param_value"));
                enumVO.setDataType(rs.getInt("data_type"));
                enumVO.setDescription(rs.getString("description"));
                enumList.add(enumVO);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        List<String> typeList = enumList.stream()
                .map(EnumVO::getParamType).distinct()
                .collect(Collectors.toList());

        for (String type : typeList) {
            List<EnumVO> mapList = new ArrayList<>();
            for (EnumVO enumVO : enumList) {
                if (type.equals(enumVO.getParamType())) {
                    mapList.add(enumVO);
                }
            }
            ret.put(type, mapList);
        }

        return ret;
    }

    private static String readEnumName(final String colComment) {
        if (colComment.contains("枚举类型")) {
            String enumName = colComment.split("枚举类型" )[1].trim();
            if (enumName.charAt(0) == ':' || enumName.charAt(0) == '：') {
                enumName = enumName.split("[:：]")[1].trim();

                enumName = enumName.split("[:：,，；; ]")[0].trim();
            }
            return enumName;
        }
        return null;
    }

    public static void main(String[] args) {
        System.out.println(readEnumName("枚举类型:AbsEnum"));
        System.out.println(readEnumName("枚举类型：AbsEnum"));
        System.out.println(readEnumName("枚举类型:  AbsEnum"));
        System.out.println(readEnumName("枚举类型：  AbsEnum"));

        System.out.println(readEnumName("枚举类型:AbsEnum，heheh"));
        System.out.println(readEnumName("枚举类型：AbsEnum  ，heheh"));
        System.out.println(readEnumName("枚举类型:  AbsEnum,heheh"));
        System.out.println(readEnumName("枚举类型：  AbsEnum  ,heheh"));
    }
}
